<?php
namespace FastPHP\Library;

class Validate
{
    protected $rule = [];
    protected $message = [];
    protected $scene = [];
    protected $currentScene = null;
    protected $error = '';
    protected $tokenKey = '__token__';

    // 静态快速验证
    public static function make($data, $rule, $message = [], $scene = null)
    {
        $v = new static();
        $v->rule = $rule;
        $v->message = $message;
        if ($scene) $v->scene($scene);
        return $v->check($data);
    }

    // 设置场景
    public function scene($scene)
    {
        $this->currentScene = $scene;
        return $this;
    }

    // 获取错误
    public function getError()
    {
        return $this->error;
    }

    // 主验证方法
    public function check($data)
    {
        $rules = $this->getSceneRule();
        foreach ($rules as $field => $ruleStr) {
            $rulesArr = explode('|', $ruleStr);
            foreach ($rulesArr as $rule) {
                $args = null;
                if (strpos($rule, ':') !== false) {
                    list($rule, $args) = explode(':', $rule, 2);
                }
                $method = 'validate' . ucfirst($rule);
                $value = isset($data[$field]) ? $data[$field] : null;
                if (method_exists($this, $method)) {
                    $result = $this->$method($value, $args);
                } else {
                    $result = $this->callBuiltin($rule, $value, $args);
                }
                if ($result !== true) {
                    $this->error = $this->getMessage($field, $rule) ?: $result;
                    return false;
                }
            }
        }
        // 表单令牌校验
        if (isset($this->rule[$this->tokenKey])) {
            if (!$this->checkToken($data[$this->tokenKey] ?? '')) {
                $this->error = $this->getMessage($this->tokenKey, 'token') ?: '表单令牌无效';
                return false;
            }
        }
        return true;
    }

    // 获取当前场景规则
    protected function getSceneRule()
    {
        if ($this->currentScene && isset($this->scene[$this->currentScene])) {
            $fields = $this->scene[$this->currentScene];
            $rules = [];
            foreach ($fields as $field) {
                if (isset($this->rule[$field])) {
                    $rules[$field] = $this->rule[$field];
                }
            }
            return $rules;
        }
        return $this->rule;
    }

    // 获取错误信息
    protected function getMessage($field, $rule)
    {
        if (isset($this->message["{$field}.{$rule}"])) {
            return $this->message["{$field}.{$rule}"];
        }
        if (isset($this->message[$field])) {
            return $this->message[$field];
        }
        return '';
    }

    // 内置规则
    protected function callBuiltin($rule, $value, $args)
    {
        switch ($rule) {
            case 'require':
                return $value !== null && $value !== '' ? true : '不能为空';
            case 'length':
                list($min, $max) = explode(',', $args);
                $len = mb_strlen($value);
                return ($len >= $min && $len <= $max) ? true : "长度必须在{$min}-{$max}之间";
            case 'email':
                return filter_var($value, FILTER_VALIDATE_EMAIL) ? true : '邮箱格式不正确';
            case 'number':
                return is_numeric($value) ? true : '必须为数字';
            case 'in':
                $arr = explode(',', $args);
                return in_array($value, $arr) ? true : '不在允许范围';
            case 'regex':
                return preg_match($args, $value) ? true : '格式错误';
            case 'token':
                return $this->checkToken($value) ? true : '表单令牌无效';
            default:
                return true;
        }
    }

    // 表单令牌校验
    public function checkToken($token)
    {
        if (empty($_SESSION)) session_start();
        $key = '__token__';
        $sessionToken = $_SESSION[$key] ?? '';
        $valid = $token && $sessionToken && $token === $sessionToken;
        // 验证后立即销毁token，防止重复提交
        unset($_SESSION[$key]);
        return $valid;
    }

    // 生成表单令牌
    public static function token()
    {
        if (empty($_SESSION)) session_start();
        $key = '__token__';
        $token = bin2hex(random_bytes(16));
        $_SESSION[$key] = $token;
        return $token;
    }
} 